﻿using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using housingsafety.server.Entities.DataModels;
using housingsafety.server.Repository;
using housingsafety.server.Repository.Extensions;
using housingsafety.server.Repository.Impl;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;

namespace housingsafety.server.Entities
{
    namespace DataModels
    {
        /// <summary>
        /// 数据库上下文
        /// </summary>
        public partial class BaseDbContext
        {
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="options"></param>
            public BaseDbContext(DbContextOptions options) : base(options)
            {
            }
        }
    }

    /// <inheritdoc />
    public partial class ZmDbContext : BaseDbContext
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public ZmDbContext()
        {
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="options">数据库上下文</param>
        public ZmDbContext(DbContextOptions<ZmDbContext> options)
            : base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            var assemblies = AppDomain.CurrentDomain.GetCurrentPathAssembly();
            //.Where(x => !(x.GetName().Name.Equals(typeof(ServiceCollectionExtension).Assembly.GetName().Name)));
            foreach (var assembly in assemblies)
            {
                var entityTypes = assembly.GetTypes()
                    .Where(type => !string.IsNullOrWhiteSpace(type.Namespace))
                    .Where(type => type.IsClass)
                    .Where(type => !type.IsAbstract)
                    .Where(type => type.Name != nameof(Entity))
                    .Where(type => !type.IsGenericType)
                    .Where(type => type.BaseType != null)
                    .Where(type => typeof(ITrack).IsAssignableFrom(type));

                foreach (var entityType in entityTypes)
                {
                    if (modelBuilder.Model.FindEntityType(entityType) != null)
                    {
                        continue;
                    }

                    modelBuilder.Model.AddEntityType(entityType);
                }
            }
            base.OnModelCreating(modelBuilder);
        }

        public override int SaveChanges()
        {
            SetTrackInfo();
            return base.SaveChanges();
        }

        public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            SetTrackInfo();
            return base.SaveChangesAsync(cancellationToken);
        }

        private void SetTrackInfo()
        {
            ChangeTracker.DetectChanges();

            var entries = Enumerable.Where<EntityEntry>(this.ChangeTracker.Entries(), x => x.Entity is ITrack)
                .Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);

            foreach (var entry in entries)
            {
                var entity = entry.Entity;
                var entityBase = entity as ITrack;
                switch (entry.State)
                {
                    case EntityState.Modified:
                        if (entityBase.IsDelete == 1)
                        {
                            entityBase.DeleteOn = DateTime.Now;
                        }
                        else
                        {
                            entityBase.ModifiedOn = DateTime.Now;
                        }
                        break;
                    case EntityState.Added:
                        entityBase.CreateOn = DateTime.Now;
                        break;
                }
            }
        }
    }
}
